package com.zmn.uac.business.impl.oauth.login;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.saas.dubbo.dto.app.AppDRO;
import com.zmn.tapi.common.wechat.WechatAccessToken;
import com.zmn.uac.business.interfaces.oauth.login.WeChatOfficialAccountLoginBService;
import com.zmn.uac.business.template.oauth.login.BaseLoginTemplateMode;
import com.zmn.uac.client.WeChatOfficiantClient;
import com.zmn.uac.common.constant.AccessTypeConstant;
import com.zmn.uac.common.constant.WeChatUrlConstant;
import com.zmn.uac.common.dio.oauth.login.TempCodeDIO;
import com.zmn.uac.common.dio.oauth.login.UserAuthLoginDIO;
import com.zmn.uac.common.entity.oauth.login.*;
import com.zmn.uac.common.entity.oauth.phone.UserPhoneInfo;
import com.zmn.uac.common.info.AuthLoginCode;
import com.zmn.uac.common.info.UserAuthPhoneInfo;
import com.zmn.uac.common.info.wechat.WeChatOfficialAccountUserInfo;
import com.zmn.uac.common.info.wechat.WeChatPersonalAccessToken;
import com.zmn.uac.util.HttpClientsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * 类描述：微信公众号登陆业务实现
 *
 * @author xujie
 * @since 2021/06/15 10:07
 */
@Slf4j
@Service
public class WeChatOfficialAccountLoginBServiceImpl extends BaseLoginTemplateMode implements WeChatOfficialAccountLoginBService {

    private static final String TAG = "微信公众号登陆业务实现";

    @Resource
    WeChatOfficiantClient weChatOfficiantClient;

    @Override
    public ResponseDTO<UserAuthLoginInfo> thirdPartyUserDataAcquisition(UserAuthLoginDIO dio, UserAuthPhoneInfo authPhoneInfo) {

        Integer channelId = dio.getChannelId();
        AppDRO app = Objects.equals(dio.getAccessType(), AccessTypeConstant.SHOP)
                ? getAppInfoByShopId(dio.getShopId()) : getAppByChannelId(channelId);
        if (Objects.isNull(app)) {
            return ResponseDTO.fail("查询应用为null");
        }
        WeChatPersonalAccessToken accessToken;
        AuthLoginCode info = (AuthLoginCode) authPhoneInfo;
        ResponseDTO<WeChatPersonalAccessToken> accessTokenResponse = getWeChatPersonalAccessToken(app.getThirdAppId(), app.getThirdAppSecret(), info.getCode());
        if (!accessTokenResponse.isSuccess()) {
            log.error("[{}], 获取用户公众号授权code信息, 入参：{}", TAG, JSONObject.toJSONString(info));
            return ResponseDTO.fail(accessTokenResponse.getMessage());
        } else {
            accessToken = accessTokenResponse.getData();
        }
        ResponseDTO<WeChatOfficialAccountUserInfo> accountUserInfoResponse = getWeChatOfficialAccountUserInfo(accessToken.getOpenid(), app.getThirdAppId(), app.getThirdAppSecret());
        if (!accountUserInfoResponse.isSuccess()) {
            return ResponseDTO.fail(accountUserInfoResponse.getMessage());
        }
        WeChatOfficialAccountUserInfo accountUserInfo = accountUserInfoResponse.getData();
        UserInfo userInfo = setUserInfo(accessToken, accountUserInfo, dio);
        PlatInfo platInfo = setPlatInfo(dio, app, channelId);
        ThirdAppInfo thirdAppInfo = setThirdAppInfo(app);
        UserOtherInfo userOtherInfo = setUserOtherInfo(accountUserInfo);
        UserAuthLoginInfo userAuthLoginInfo = setUserAuthLoginInfo(userInfo, userOtherInfo, platInfo, thirdAppInfo);

        return ResponseDTO.success(userAuthLoginInfo);
    }

    @Override
    public ResponseDTO<String> getThirdPartyOpenIdByCode(TempCodeDIO tempCodeDIO, AppDRO app) {
        ResponseDTO<WeChatPersonalAccessToken> accessTokenResponse =
                getWeChatPersonalAccessToken(app.getThirdAppId(), app.getThirdAppSecret(), tempCodeDIO.getCode());
        if (!accessTokenResponse.isSuccess()) {
            log.error("[{}], 获取用户公众号授权code信息, 入参：tempCodeDIO = {}", TAG, JSONObject.toJSONString(tempCodeDIO));
            return ResponseDTO.fail(accessTokenResponse.getMessage());
        }
        log.info("获取公众号调用响应responseDTO:{}", accessTokenResponse.getData());
        return ResponseDTO.success(accessTokenResponse.getData().getOpenid());
    }

    private ResponseDTO<WeChatPersonalAccessToken> getWeChatPersonalAccessToken(String appId, String secret, String code) {
        String requestCodeUrl = String.format(WeChatUrlConstant.OAUTH_2_URL, appId, secret, code);
        String jsonResult;
        try {
            jsonResult = HttpClientsUtil.executeGet(requestCodeUrl);
        } catch (Exception e) {
            log.error("[{}], 获取用户公众号授权code信息异常, 参数appId:{}, Secret:{}, code:{}, msg:{}", TAG, appId, secret, code, e.getMessage(), e);
            return ResponseDTO.fail("获取用户公众号授权code信息异常");
        }
        WeChatPersonalAccessToken accessToken = JSON.parseObject(jsonResult, WeChatPersonalAccessToken.class);
        if (accessToken == null || accessToken.getOpenid() == null) {
            log.error("[{}], 获取用户公众号授权code信息失败, 参数appId:{}, Secret:{}, code:{}, jsonResult:{}", TAG, appId, secret, code, jsonResult);
            return ResponseDTO.fail("获取用户公众号授权code信息失败");
        } else {
            return ResponseDTO.success(accessToken);
        }
    }

    private ResponseDTO<WeChatOfficialAccountUserInfo> getWeChatOfficialAccountUserInfo(String openid, String appId, String secret) {
        ResponseDTO<String> response = getGlobalAccessToken(appId, secret);
        if (!response.isSuccess()) {
            return ResponseDTO.fail(response.getMessage());
        }
        String accessToken = response.getData();
        String requestUserInfoUrl = String.format(WeChatUrlConstant.USER_INFO_URL, accessToken, openid);
        String jsonResult;
        try {
            jsonResult = HttpClientsUtil.executeGet(requestUserInfoUrl);
        } catch (Exception e) {
            log.error("[{}], 获取用户公众号信息异常, 参数openid:{}, appId:{}, Secret:{}, accessToken:{}, msg:{}", TAG, openid, appId, secret, accessToken, e.getMessage(), e);
            return ResponseDTO.fail("获取用户公众号信息异常");
        }
        log.info("[{}],  获取用户公众号信息jsonResult: {}", TAG, jsonResult);
        WeChatOfficialAccountUserInfo accountUserInfo = JSON.parseObject(jsonResult, WeChatOfficialAccountUserInfo.class);
        if (accountUserInfo == null) {
            log.error("[{}], 获取用户公众号信息失败, 参数openid:{}, appId:{}, Secret:{}, accessToken:{}, jsonResult:{}", TAG, openid, appId, secret, accessToken, jsonResult);
            return ResponseDTO.fail("获取用户公众号信息失败");
        } else {
            return ResponseDTO.success(accountUserInfo);
        }
    }

    private ResponseDTO<String> getGlobalAccessToken(String appId, String secret) {
        WechatAccessToken wechatAccessToken = weChatOfficiantClient.token(appId, secret);
        return ResponseDTO.success(wechatAccessToken.getToken());
    }

    private UserInfo setUserInfo(WeChatPersonalAccessToken accessToken,WeChatOfficialAccountUserInfo accountUserInfo,UserAuthLoginDIO dio){
        Integer gender = (accountUserInfo.getSex() != null && accountUserInfo.getSex() != 0) ? accountUserInfo.getSex() : 3;
        return UserInfo.builder()
                .userId(null)
                .openId(accessToken.getOpenid())
                .unionId(accountUserInfo.getUnionId() == null ? accessToken.getOpenid() : accountUserInfo.getUnionId())
                .type(GlobalConsts.NO)
                .realname(StringUtil.isBlank(accountUserInfo.getNickname()) ? "微信用户" : dio.getNickName())
                .username(null)
                .nickName(accountUserInfo.getNickname())
                .avatarSrc(StringUtils.isNotBlank(accountUserInfo.getHeadImgUrl()) ? accountUserInfo.getHeadImgUrl() : accountUserInfo.getAvatarUrl())
                .age(null)
                .gender(gender)
                .country(accountUserInfo.getCountry())
                .province(accountUserInfo.getProvince())
                .city(accountUserInfo.getCity())
                .build();
    }

    private PlatInfo setPlatInfo(UserAuthLoginDIO dio,AppDRO app,Integer channelId){
        return PlatInfo.builder()
                .shopId(dio.getShopId())
                .plat(app.getPlat())
                .channelId(channelId)
                .channelName(getNameByChannelId(channelId))
                .entrance(dio.getEntrance())
                .build();
    }

    private ThirdAppInfo setThirdAppInfo(AppDRO app){
        return ThirdAppInfo.builder()
                .appId(app.getThirdAppId())
                .appName(app.getName())
                .appSecret(app.getThirdAppSecret())
                .build();
    }

    private UserOtherInfo setUserOtherInfo(WeChatOfficialAccountUserInfo accountUserInfo){
        return UserOtherInfo.builder()
                .language(accountUserInfo.getLanguage())
                .groupId(Objects.nonNull(accountUserInfo.getGroupId()) ? accountUserInfo.getGroupId().toString() : null)
                .qrScene(Objects.nonNull(accountUserInfo.getQrScene()) ? accountUserInfo.getQrScene().toString() : null)
                .qrSceneStr(accountUserInfo.getQrSceneStr())
                .subscribe(accountUserInfo.getSubscribe())
                .subscribeScene(accountUserInfo.getSubscribeScene())
                .tagIds(accountUserInfo.getTagIdList())
                .remark(accountUserInfo.getRemark())
                .subscribe(accountUserInfo.getSubscribe())
                .subscribeTime(accountUserInfo.getSubscribeTime())
                .build();
    }

    private UserAuthLoginInfo setUserAuthLoginInfo(UserInfo userInfo,UserOtherInfo userOtherInfo,PlatInfo platInfo,ThirdAppInfo thirdAppInfo){
        return UserAuthLoginInfo.builder()
                .userInfo(userInfo)
                .userOtherInfo(userOtherInfo)
                .platInfo(platInfo)
                .thirdAppInfo(thirdAppInfo)
                .userPhoneInfo(new UserPhoneInfo())
                .build();
    }
}
